//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_testcase_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/comment_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_review_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/testcase_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/watch_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_testcase"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_comment_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_recycle_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_review_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_testcase_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_watch_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectTestCaseApiImpl) CreateCase(ctx context.Context, req *project_testcase_api.CreateCaseRequest) (*project_testcase_api.CreateCaseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.CreateCaseResponse{
			Code:   project_testcase_api.CreateCaseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.CreateCaseResponse{
			Code:   project_testcase_api.CreateCaseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.CreateCaseResponse{
			Code:   project_testcase_api.CreateCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.CreateCaseResponse{
			Code:   project_testcase_api.CreateCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查父目录是否存在
	if req.ParentFolderId != "" {
		exist, err := testcase_dao.FolderInfoDao.Exist(ctx, req.ParentFolderId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_testcase_api.CreateCaseResponse{
				Code:   project_testcase_api.CreateCaseResponse_CODE_NO_PARENT_FOLDER,
				ErrMsg: "父目录不存在",
			}, nil
		}
	}

	caseId := uuid.NewString()
	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.CaseInfoDao.Insert(sessCtx, &testcase_dao.CaseInfoDbItem{
			CaseId:         caseId,
			ProjectId:      req.ProjectId,
			Title:          req.Title,
			ParentFolderId: req.ParentFolderId,
			PermSetting: testcase_dao.PermSettingDbItem{
				UpdateForAll:          req.PermSetting.UpdateForAll,
				ExtraUpdateUserIdList: req.PermSetting.ExtraUpdateUserIdList,
			},
			TestMethod: testcase_dao.TestMethodDbItem{
				UnitTest:   req.TestMethod.UnitTest,
				CiTest:     req.TestMethod.CiTest,
				LoadTest:   req.TestMethod.LoadTest,
				ManualTest: req.TestMethod.ManualTest,
			},
			CreateUserId: sessionItem.UserId,
			CreateTime:   timeNow,
			UpdateUserId: sessionItem.UserId,
			UpdateTime:   timeNow,
		})
		if err != nil {
			return nil, err
		}
		err = dao.MsgDataDao.Insert(sessCtx, &dao.MsgDataDBItem{
			MsgId:        caseId,
			Content:      req.Content,
			CreateUserId: sessionItem.UserId,
			CreateTime:   timeNow,
			HasChanged:   false,
		})
		if req.ParentFolderId != "" {
			count, err := testcase_dao.CaseInfoDao.CountSubCase(sessCtx, req.ParentFolderId, req.ProjectId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.FolderInfoDao.UpdateSubCaseCount(sessCtx, req.ParentFolderId, req.ProjectId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_testcase_api.CreateCaseResponse{
			Code:   project_testcase_api.CreateCaseResponse_CODE_OK,
			CaseId: caseId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCreateCaseEvent(sessionItem, req, projectItem, caseId, timeNow)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.NewCaseNotice{
		ProjectId:    req.ProjectId,
		CaseId:       caseId,
		CreateUserId: sessionItem.UserId,
	})
	return ret.(*project_testcase_api.CreateCaseResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) UpdateCase(ctx context.Context, req *project_testcase_api.UpdateCaseRequest) (*project_testcase_api.UpdateCaseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}

	userPerm := apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	if !userPerm.CanUpdate {
		return &project_testcase_api.UpdateCaseResponse{
			Code:   project_testcase_api.UpdateCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.CaseInfoDao.Update(sessCtx, req.CaseId, req.ProjectId, req.Title,
			&testcase_dao.TestMethodDbItem{
				UnitTest:   req.TestMethod.UnitTest,
				CiTest:     req.TestMethod.CiTest,
				LoadTest:   req.TestMethod.LoadTest,
				ManualTest: req.TestMethod.ManualTest,
			}, sessionItem.UserId, timeNow)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.UpdateCaseResponse{
			Code: project_testcase_api.UpdateCaseResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUpdateCaseEvent(sessionItem, req, projectItem, caseItem.Title, timeNow)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.UpdateCaseResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) UpdateCaseContent(ctx context.Context, req *project_testcase_api.UpdateCaseContentRequest) (*project_testcase_api.UpdateCaseContentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}

	userPerm := apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	if !userPerm.CanUpdate {
		return &project_testcase_api.UpdateCaseContentResponse{
			Code:   project_testcase_api.UpdateCaseContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = dao.MsgDataDao.Update(sessCtx, req.CaseId, req.Content)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.UpdateCaseContentResponse{
			Code: project_testcase_api.UpdateCaseContentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.UpdateCaseContentResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListCase(ctx context.Context, req *project_testcase_api.ListCaseRequest) (*project_testcase_api.ListCaseResponse, error) {
	emptyList := []*project_testcase_api.CaseInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListCaseResponse{
			Code:     project_testcase_api.ListCaseResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			CaseList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListCaseResponse{
			Code:     project_testcase_api.ListCaseResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			CaseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListCaseResponse{
			Code:     project_testcase_api.ListCaseResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			CaseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查目录是否存在
	if req.ParentFolderId != "" {
		exist, err := testcase_dao.FolderInfoDao.Exist(ctx, req.ParentFolderId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_testcase_api.ListCaseResponse{
				Code:     project_testcase_api.ListCaseResponse_CODE_NO_PARENT_FOLDER,
				ErrMsg:   "父目录不存在",
				CaseList: emptyList,
			}, nil
		}
	}

	caseItemList, err := testcase_dao.CaseInfoDao.ListSubCase(ctx, req.ParentFolderId, req.ProjectId)
	if err != nil {
		return nil, err
	}

	caseIdList := []string{}
	userIdList := []string{}
	for _, caseItem := range caseItemList {
		caseIdList = append(caseIdList, caseItem.CaseId)
		userIdList = append(userIdList, caseItem.CreateUserId)
		userIdList = append(userIdList, caseItem.UpdateUserId)
	}

	//获取关注信息
	watchItemMap, _, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), caseIdList)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	caseList := []*project_testcase_api.CaseInfo{}
	for _, caseItem := range caseItemList {
		caseInfo := caseItem.ToCaseInfo()
		createUser, ok := userItemMap[caseItem.CreateUserId]
		if ok {
			caseInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
			caseInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[caseItem.UpdateUserId]
		if ok {
			caseInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			caseInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		caseInfo.UserPerm = apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
		watchUserIdList, ok := watchItemMap[caseItem.CaseId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					caseInfo.MyWatch = true
				}
			}
		}
		caseList = append(caseList, caseInfo)
	}
	return &project_testcase_api.ListCaseResponse{
		Code:     project_testcase_api.ListCaseResponse_CODE_OK,
		CaseList: caseList,
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListCaseById(ctx context.Context, req *project_testcase_api.ListCaseByIdRequest) (*project_testcase_api.ListCaseByIdResponse, error) {
	emptyList := []*project_testcase_api.CaseInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListCaseByIdResponse{
			Code:     project_testcase_api.ListCaseByIdResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			CaseList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListCaseByIdResponse{
			Code:     project_testcase_api.ListCaseByIdResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			CaseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListCaseByIdResponse{
			Code:     project_testcase_api.ListCaseByIdResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			CaseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	caseItemList, err := testcase_dao.CaseInfoDao.ListById(ctx, req.ProjectId, req.CaseIdList)
	if err != nil {
		return nil, err
	}

	userIdList := []string{}
	for _, caseItem := range caseItemList {
		userIdList = append(userIdList, caseItem.CreateUserId)
		userIdList = append(userIdList, caseItem.UpdateUserId)
	}

	//获取关注信息
	watchItemMap, _, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), req.CaseIdList)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	caseList := []*project_testcase_api.CaseInfo{}
	for _, caseItem := range caseItemList {
		caseInfo := caseItem.ToCaseInfo()
		createUser, ok := userItemMap[caseItem.CreateUserId]
		if ok {
			caseInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
			caseInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[caseItem.UpdateUserId]
		if ok {
			caseInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			caseInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		caseInfo.UserPerm = apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
		watchUserIdList, ok := watchItemMap[caseItem.CaseId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					caseInfo.MyWatch = true
				}
			}
		}
		caseList = append(caseList, caseInfo)
	}

	return &project_testcase_api.ListCaseByIdResponse{
		Code:     project_testcase_api.ListCaseByIdResponse_CODE_OK,
		CaseList: caseList,
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListCaseFlat(ctx context.Context, req *project_testcase_api.ListCaseFlatRequest) (*project_testcase_api.ListCaseFlatResponse, error) {
	emptyList := []*project_testcase_api.CaseInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListCaseFlatResponse{
			Code:     project_testcase_api.ListCaseFlatResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			CaseList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListCaseFlatResponse{
			Code:     project_testcase_api.ListCaseFlatResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			CaseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListCaseFlatResponse{
			Code:     project_testcase_api.ListCaseFlatResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			CaseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	count := uint32(0)
	caseItemList := []*testcase_dao.CaseInfoDbItem{}
	if req.ListParam.MyWatch {
		caseIdList, err := watch_dao.MyWatchDao.DistinctTargetId(ctx, req.ProjectId, sessionItem.UserId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE))
		if err != nil {
			return nil, err
		}
		count, err = testcase_dao.CaseInfoDao.CountWithParamById(ctx, req.ProjectId, caseIdList, req.ListParam)
		if err != nil {
			return nil, err
		}
		caseItemList, err = testcase_dao.CaseInfoDao.ListWithParamById(ctx, req.ProjectId, caseIdList, req.ListParam, int64(req.Offset), int64(req.Limit))
		if err != nil {
			return nil, err
		}
	} else {
		count, err = testcase_dao.CaseInfoDao.CountWithParam(ctx, req.ProjectId, req.ListParam)
		if err != nil {
			return nil, err
		}
		caseItemList, err = testcase_dao.CaseInfoDao.ListWithParam(ctx, req.ProjectId, req.ListParam, int64(req.Offset), int64(req.Limit))
		if err != nil {
			return nil, err
		}
	}

	caseIdList := []string{}
	userIdList := []string{}
	for _, caseItem := range caseItemList {
		caseIdList = append(caseIdList, caseItem.CaseId)
		userIdList = append(userIdList, caseItem.CreateUserId)
		userIdList = append(userIdList, caseItem.UpdateUserId)
	}

	//获取关注信息
	watchItemMap, _, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), caseIdList)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	caseList := []*project_testcase_api.CaseInfo{}
	for _, caseItem := range caseItemList {
		caseInfo := caseItem.ToCaseInfo()
		createUser, ok := userItemMap[caseItem.CreateUserId]
		if ok {
			caseInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
			caseInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[caseItem.UpdateUserId]
		if ok {
			caseInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			caseInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		caseInfo.UserPerm = apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
		watchUserIdList, ok := watchItemMap[caseItem.CaseId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					caseInfo.MyWatch = true
				}
			}
		}
		caseList = append(caseList, caseInfo)
	}

	return &project_testcase_api.ListCaseFlatResponse{
		Code:     project_testcase_api.ListCaseFlatResponse_CODE_OK,
		Count:    count,
		CaseList: caseList,
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) ListAllCase(ctx context.Context, req *project_testcase_api.ListAllCaseRequest) (*project_testcase_api.ListAllCaseResponse, error) {
	emptyList := []*project_testcase_api.SimpleCaseInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.ListAllCaseResponse{
			Code:     project_testcase_api.ListAllCaseResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			CaseList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.ListAllCaseResponse{
			Code:     project_testcase_api.ListAllCaseResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			CaseList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.ListAllCaseResponse{
			Code:     project_testcase_api.ListAllCaseResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			CaseList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	caseItemList, err := testcase_dao.CaseInfoDao.ListByProject(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	caseList := []*project_testcase_api.SimpleCaseInfo{}
	for _, caseItem := range caseItemList {
		caseList = append(caseList, &project_testcase_api.SimpleCaseInfo{
			CaseId:         caseItem.CaseId,
			Title:          caseItem.Title,
			ParentFolderId: caseItem.ParentFolderId,
		})
	}

	return &project_testcase_api.ListAllCaseResponse{
		Code:     project_testcase_api.ListAllCaseResponse_CODE_OK,
		CaseList: caseList,
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) GetCase(ctx context.Context, req *project_testcase_api.GetCaseRequest) (*project_testcase_api.GetCaseResponse, error) {
	emptyInfo := &project_testcase_api.CaseDetailInfo{
		CaseInfo: &project_testcase_api.CaseInfo{
			PermSetting: &project_testcase_api.PermSetting{
				ExtraUpdateUserIdList: []string{},
			},
			TestMethod: &project_testcase_api.TestMethod{},
			UserPerm:   &project_testcase_api.UserPerm{},
		},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.GetCaseResponse{
			Code:       project_testcase_api.GetCaseResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			CaseDetail: emptyInfo,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.GetCaseResponse{
			Code:       project_testcase_api.GetCaseResponse_CODE_NO_PROJECT,
			ErrMsg:     "项目不存在",
			CaseDetail: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.GetCaseResponse{
			Code:       project_testcase_api.GetCaseResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			CaseDetail: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.GetCaseResponse{
			Code:       project_testcase_api.GetCaseResponse_CODE_NO_CASE,
			ErrMsg:     "测试用例不存在",
			CaseDetail: emptyInfo,
		}, nil
	}
	contentItem, err := dao.MsgDataDao.Get(ctx, req.CaseId)
	if err != nil {
		return &project_testcase_api.GetCaseResponse{
			Code:       project_testcase_api.GetCaseResponse_CODE_NO_CASE,
			ErrMsg:     "测试用例不存在",
			CaseDetail: emptyInfo,
		}, nil
	}

	//获取关注信息
	watchItemMap, _, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), []string{req.CaseId})
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{caseItem.CreateUserId, caseItem.UpdateUserId})
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	caseInfo := caseItem.ToCaseInfo()
	createUser, ok := userItemMap[caseItem.CreateUserId]
	if ok {
		caseInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
		caseInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
	}
	updateUser, ok := userItemMap[caseItem.UpdateUserId]
	if ok {
		caseInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
		caseInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
	}
	caseInfo.UserPerm = apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	watchUserIdList, ok := watchItemMap[caseItem.CaseId]
	if ok {
		for _, watchUserId := range watchUserIdList {
			if watchUserId == sessionItem.UserId {
				caseInfo.MyWatch = true
			}
		}
	}

	if req.SpritId != "" {
		linkItem, err := testcase_dao.LinkSpritDao.Get(ctx, req.CaseId, req.SpritId)
		if err != nil { //没有关联工作计划
			caseInfo.ResultCount = 0
		} else {
			caseInfo.ResultCount = linkItem.ResultCount
		}
	}

	return &project_testcase_api.GetCaseResponse{
		Code: project_testcase_api.GetCaseResponse_CODE_OK,
		CaseDetail: &project_testcase_api.CaseDetailInfo{
			CaseInfo: caseInfo,
			Content:  contentItem.Content,
		},
	}, nil
}

func (apiImpl *ProjectTestCaseApiImpl) SetCaseParent(ctx context.Context, req *project_testcase_api.SetCaseParentRequest) (*project_testcase_api.SetCaseParentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_CASE,
			ErrMsg: "测试用例不存在",
		}, nil
	}

	userPerm := apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	if !userPerm.CanUpdate {
		return &project_testcase_api.SetCaseParentResponse{
			Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if req.ParentFolderId != "" {
		exist, err := testcase_dao.FolderInfoDao.Exist(ctx, req.ParentFolderId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_testcase_api.SetCaseParentResponse{
				Code:   project_testcase_api.SetCaseParentResponse_CODE_NO_PARENT_FOLDER,
				ErrMsg: "目标目录不存在",
			}, nil
		}
	}

	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.CaseInfoDao.UpdateParentFolder(sessCtx, req.CaseId, req.ProjectId, req.ParentFolderId, sessionItem.UserId, timeNow)
		if err != nil {
			return nil, err
		}
		if caseItem.ParentFolderId != "" {
			count, err := testcase_dao.CaseInfoDao.CountSubCase(sessCtx, caseItem.ParentFolderId, req.ProjectId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.FolderInfoDao.UpdateSubCaseCount(sessCtx, caseItem.ParentFolderId, req.ProjectId, count)
			if err != nil {
				return nil, err
			}
		}
		if req.ParentFolderId != "" {
			count, err := testcase_dao.CaseInfoDao.CountSubCase(sessCtx, req.ParentFolderId, req.ProjectId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.FolderInfoDao.UpdateSubCaseCount(sessCtx, req.ParentFolderId, req.ProjectId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_testcase_api.SetCaseParentResponse{
			Code: project_testcase_api.SetCaseParentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.SetCaseParentResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) RemoveCase(ctx context.Context, req *project_testcase_api.RemoveCaseRequest) (*project_testcase_api.RemoveCaseResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.RemoveCaseResponse{
			Code:   project_testcase_api.RemoveCaseResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.RemoveCaseResponse{
			Code:   project_testcase_api.RemoveCaseResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.RemoveCaseResponse{
			Code:   project_testcase_api.RemoveCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.RemoveCaseResponse{
			Code:   project_testcase_api.RemoveCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil { //测试用例不存在
		return &project_testcase_api.RemoveCaseResponse{
			Code: project_testcase_api.RemoveCaseResponse_CODE_OK,
		}, nil
	}

	userPerm := apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	if !userPerm.CanRemove {
		return &project_testcase_api.RemoveCaseResponse{
			Code:   project_testcase_api.RemoveCaseResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.CaseInfoDao.Remove(sessCtx, req.CaseId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		err = testcase_dao.CaseRecycleDao.Insert(sessCtx, caseItem)
		if err != nil {
			return nil, err
		}

		err = project_dao.RecycleDao.Insert(sessCtx, &project_dao.RecycleItemInfoDbItem{
			RecycleItemId:   req.CaseId,
			ProjectId:       req.ProjectId,
			RecycleItemType: uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_TESTCASE),
			RemoveUserId:    sessionItem.UserId,
			RemoveTime:      nowTime,
		})
		if err != nil {
			return nil, err
		}

		if caseItem.ParentFolderId != "" {
			count, err := testcase_dao.CaseInfoDao.CountSubCase(sessCtx, caseItem.ParentFolderId, req.ProjectId)
			if err != nil {
				return nil, err
			}
			err = testcase_dao.FolderInfoDao.UpdateSubCaseCount(sessCtx, caseItem.ParentFolderId, req.ProjectId, count)
			if err != nil {
				return nil, err
			}
		}
		//删除关注
		err = watch_dao.MyWatchDao.RemoveByTarget(sessCtx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_TEST_CASE), req.CaseId)
		if err != nil {
			return nil, err
		}
		//删除未读评论通知
		err = comment_dao.UnReadDao.RemoveByTarget(sessCtx, req.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_TEST_CASE), req.CaseId)
		if err != nil {
			return nil, err
		}
		//取消工作计划关联
		err = testcase_dao.LinkSpritDao.RemoveByCase(sessCtx, req.CaseId)
		if err != nil {
			return nil, err
		}
		//删除复盘链接
		err = project_review_dao.LinkDao.RemoveByTarget(sessCtx, req.ProjectId, req.CaseId, project_review_api.LINK_TYPE_LINK_TYPE_TEST_CASE)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.RemoveCaseResponse{
			Code: project_testcase_api.RemoveCaseResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveCaseEvent(sessionItem, projectItem, caseItem, nowTime)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.RemoveCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.RemoveCaseResponse), nil
}

func (apiImpl *ProjectTestCaseApiImpl) UpdateCasePerm(ctx context.Context, req *project_testcase_api.UpdateCasePermRequest) (*project_testcase_api.UpdateCasePermResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_testcase_api.UpdateCasePermResponse{
			Code:   project_testcase_api.UpdateCasePermResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_testcase_api.UpdateCasePermResponse{
			Code:   project_testcase_api.UpdateCasePermResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_testcase_api.UpdateCasePermResponse{
			Code:   project_testcase_api.UpdateCasePermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_testcase_api.UpdateCasePermResponse{
			Code:   project_testcase_api.UpdateCasePermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	caseItem, err := testcase_dao.CaseInfoDao.Get(ctx, req.CaseId, req.ProjectId)
	if err != nil { //测试用例不存在
		return &project_testcase_api.UpdateCasePermResponse{
			Code: project_testcase_api.UpdateCasePermResponse_CODE_OK,
		}, nil
	}

	userPerm := apiImpl.calcCasePerm(sessionItem, projectItem, roleItem, caseItem)
	if !userPerm.CanUpdate {
		return &project_testcase_api.UpdateCasePermResponse{
			Code:   project_testcase_api.UpdateCasePermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	timeNow := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = testcase_dao.CaseInfoDao.UpdatePermSetting(sessCtx, req.CaseId, req.ProjectId,
			&testcase_dao.PermSettingDbItem{
				UpdateForAll:          req.PermSetting.UpdateForAll,
				ExtraUpdateUserIdList: req.PermSetting.ExtraUpdateUserIdList,
			}, sessionItem.UserId, timeNow)
		if err != nil {
			return nil, err
		}
		return &project_testcase_api.UpdateCasePermResponse{
			Code: project_testcase_api.UpdateCasePermResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_testcase.UpdateCaseNotice{
		ProjectId: req.ProjectId,
		CaseId:    req.CaseId,
	})
	return ret.(*project_testcase_api.UpdateCasePermResponse), nil
}
